package all.com.jinyongqunxiax.model.mod;

import com.randy.fundation.FileUtils;
import com.randy.fundation.ImageUitls;
import com.randy.fundation.Logger;
import com.randy.fundation.MD5Utils;

import org.apache.commons.io.FilenameUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import androidx.annotation.NonNull;
import wx.xml.stax.api.parsers.DocumentBuilder;
import wx.xml.stax.api.parsers.DocumentBuilderFactory;
import wx.xml.stax.api.transform.OutputKeys;
import wx.xml.stax.api.transform.Transformer;
import wx.xml.stax.api.transform.TransformerFactory;
import wx.xml.stax.api.transform.dom.DOMSource;
import wx.xml.stax.api.transform.stream.StreamResult;

public class DataManager {
    public Map<String, Data> datas = new HashMap<>();
    String xmlPath;

    public DataManager(@NonNull String xmlPath) {
        this.xmlPath = xmlPath;
    }

    public void updateImages(Data data, String modRoot) {
        String path     = FilenameUtils.concat(modRoot, data.fileName());
        String fileHash = MD5Utils.fileMD5(path);
        data.hash = fileHash;
        String ext = FilenameUtils.getExtension(path);
        if ("png".equals(ext) || "jpg".equals(ext) || "jpeg".equals(ext)) {
            ImageUitls.ImageSize size = ImageUitls.getImageSize(path);
            data.width = size.width;
            data.height = size.height;
        }
    }

    public String load() {
        // 扫描目录 自动重建
        try {
            String modRoot = xmlPath;
            modRoot = modRoot.replace(FilenameUtils.getName(xmlPath), "");
            Logger.d("root form xml path : %s", modRoot);

            String finalModRoot1 = modRoot;
            Logger.d("find files in :%s", finalModRoot1);
            FileUtils.walk(new File(modRoot), FileUtils.UNLIMITED_DEPTH, (dir, name)
                -> !(name.contains(".bak") || name.contains(".xsd") || name.contains("zip")), file
                -> {
                String path = file.getPath();
                String hash = MD5Utils.fileMD5(file);
                String url  = path.replace(finalModRoot1, "");

                String name = FilenameUtils.removeExtension(url);
                String ext  = FilenameUtils.getExtension(url);

                int    width  = 0;
                int    height = 0;
                String cache  = "false";
                if ("png".equals(ext) || "jpg".equals(ext) || "jpeg".equals(ext)) {
                    ImageUitls.ImageSize size = ImageUitls.getImageSize(path);
                    width = size.width;
                    height = size.height;
                    cache = "true";
                }
                datas.put(name, new Data(name, ext, hash, "" + width, "" + height, cache));
            });

            save();
        } catch (Exception e) {
            return e.getMessage();
        }

        return "";
    }

    public void save() {
        String timeStamp  = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss", Locale.getDefault()).format(new Date());
        String xmlPathBak = xmlPath + "-" + timeStamp + ".bak.xml";
        String xmlPathTmp = xmlPath + "-" + timeStamp + ".temp.xml";

        File sourceFile = new File(xmlPath);
        File backupFile = new File(xmlPathBak);
        // 备份源文件
        try {
            org.apache.commons.io.FileUtils.copyFile(sourceFile, backupFile);
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder        dBuilder  = dbFactory.newDocumentBuilder();
            Document               doc       = dBuilder.newDocument();

            Element rootElement = doc.createElement("root");

            //append root element to document
            doc.appendChild(rootElement);

            String modRoot = xmlPath;
            modRoot = modRoot.replace(FilenameUtils.getName(xmlPath), "");
            Logger.d("root form xml path : %s", modRoot);

            for (Map.Entry<String, Data> entry : datas.entrySet()) {
                Element dataNode = doc.createElement("data");
                Data    data     = entry.getValue();

                updateImages(data, modRoot);

                dataNode.setAttribute("hash", data.hash);
                dataNode.setAttribute("url", data.fileName());

                if (data.width > 0) {
                    dataNode.setAttribute("w", "" + data.width);
                }

                if (data.height > 0) {
                    dataNode.setAttribute("h", "" + data.height);
                }

                if (data.cache) {
                    dataNode.setAttribute("cache", "true");
                }

                rootElement.appendChild(dataNode);
            }

            javax.xml.transform.TransformerFactory transformerFactory = TransformerFactory.newInstance();

            DOMSource source = new DOMSource(doc);

            OutputStream output      = new FileOutputStream(xmlPath);
            StreamResult result      = new StreamResult(output);
            javax.xml.transform.Transformer  transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            //transformer.transform(source, result);
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void updateMD5(String component, String item, String modRoot) {
        String key = FilenameUtils.concat(component, item);
        key = FilenameUtils.removeExtension(key);
        Data data = datas.get(key);
        if (data == null) {
            Logger.w("%s not exist", key);
            return;
        }
        String path     = FilenameUtils.concat(modRoot, data.fileName());
        String fileHash = MD5Utils.fileMD5(path);
        if (!fileHash.equals(data.hash)) {
            data.hash = fileHash;
            String ext = FilenameUtils.getExtension(path);
            if ("png".equals(ext) || "jpg".equals(ext) || "jpeg".equals(ext)) {
                ImageUitls.ImageSize size = ImageUitls.getImageSize(path);
                data.width = size.width;
                data.height = size.height;
            }

            // save data xml
            save();
        }
    }

    public class Data {
        public String  hash;
        public int     width;
        public int     height;
        public boolean cache;
        /**
         * url=name+ext
         */
        String name;
        String ext;

        Data(String name, String ext, String hash, String width, String height, String cache) {
            this.name = name;
            this.ext = ext;
            this.hash = hash;
            try {
                this.width = Integer.parseInt(width);
            } catch (Exception e) {
                this.width = 0;
            }
            try {
                this.height = Integer.parseInt(height);
            } catch (Exception e) {
                this.height = 0;
            }
            try {
                this.cache = Boolean.parseBoolean(cache);
            } catch (Exception e) {
                this.cache = false;
            }
        }

        public String fileName() {
            try {
                return name + "." + ext;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "";
        }
    }
}
